#include <gl\glew.h>

#include <wx/wx.h>
#include <wx/glcanvas.h>
#include <wx/dir.h>

#include "Controls\OGL\Control2D.h"

#define PROGRAM_NAME "MSchemV"
#define PROGRAM_DEV "Beta"
#define PROGRAM_VERSION "0.0.0.7"

#define PROGRAM_VERSION_STRING PROGRAM_NAME" "PROGRAM_DEV" "PROGRAM_VERSION
static const wxString verString(PROGRAM_VERSION_STRING);

#include "ModuleWindow.h"

class MyApp : public wxApp
{
public:
    bool OnInit();
    int OnExit();
};

class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);

	void SetSchematic (Schematic *schematic);

private:
	Schematic *_schem;
	class wxViewportGLCanvas *_viewport0, *_viewport1, *_viewport2, *_viewport3;
	wxGLContext *_context0, *_context1, *_context2, *_context3;
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
	void OnZoomOut(wxCommandEvent& event);
	void OnZoomIn(wxCommandEvent& event);
	void OnTexturePack(wxCommandEvent& event);
	void OnModules(wxCommandEvent& event);
    wxDECLARE_EVENT_TABLE();

	std::map<int, wxString> TexturePacks;
	wxMenuItem *SelectedTP;
};

class wxViewportGLCanvas : public wxGLCanvas
{
    wxDECLARE_EVENT_TABLE();
	wxGLContext *_context;
	wxControl2D *_control;

public:
	static wxGLRenderer *_renderer;

	wxViewportGLCanvas(wxWindow *parent) :
		wxGLCanvas(parent),
		_control(nullptr)
	{
		if (_renderer == nullptr)
		{
			_renderer = new wxGLRenderer();
			_renderer->CreateWorkers();
		}
	}

	~wxViewportGLCanvas()
	{
		delete _control;
		delete _renderer;
	}

	void CreateContext(wxGLContext *owner = nullptr)
	{
		_context = new wxGLContext(this, owner);
	}

	wxGLContext *GetContext() const { return _context; }

	void CreateControl(const Viewport &viewport)
	{
		_control = new wxControl2D(this, _context, _renderer, viewport);
		_control->Renderer->SetTexturePack("");
	}

	wxControl2D *GetControl() const { return _control; }

	void Paint(wxPaintEvent &event)
	{
		if (_control != nullptr)
			_control->control_Paint(event);
	}

	void Size(wxSizeEvent &event)
	{
		if (_control != nullptr)
			_control->control_SizeChanged(event);
	}

	void MouseWheel(wxMouseEvent &event)
	{
		if (_control != nullptr)
			_control->control_MouseWheel(event);
	}

	void MouseDown(wxMouseEvent &event)
	{
		if (_control != nullptr)
			_control->control_MouseDown(event);
	}

	void MouseUp(wxMouseEvent &event)
	{
		if (_control != nullptr)
			_control->control_MouseUp(event);
	}

	void Motion(wxMouseEvent &event)
	{
		if (_control != nullptr)
			_control->control_MouseMove(event);
	}

	void EnterWindow (wxMouseEvent &event)
	{
		SetFocus();
	}
};

wxGLRenderer *wxViewportGLCanvas::_renderer = nullptr;

wxBEGIN_EVENT_TABLE(wxViewportGLCanvas, wxGLCanvas)
	EVT_PAINT(wxViewportGLCanvas::Paint)
	EVT_SIZE(wxViewportGLCanvas::Size)
	EVT_MOUSEWHEEL(wxViewportGLCanvas::MouseWheel)
	EVT_LEFT_DOWN(wxViewportGLCanvas::MouseDown)
	EVT_LEFT_UP(wxViewportGLCanvas::MouseUp)
	EVT_RIGHT_DOWN(wxViewportGLCanvas::MouseDown)
	EVT_RIGHT_UP(wxViewportGLCanvas::MouseUp)
	EVT_MIDDLE_DOWN(wxViewportGLCanvas::MouseDown)
	EVT_MIDDLE_UP(wxViewportGLCanvas::MouseUp)
	EVT_MOTION(wxViewportGLCanvas::Motion)
	EVT_ENTER_WINDOW(wxViewportGLCanvas::EnterWindow)
wxEND_EVENT_TABLE()

enum
{
    ID_Hello = 1,
	
	ID_Texturepack0 = 10000,
	ID_TexturepackEnd = 10100,
	ID_Modules = 9999,
};

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
	: wxFrame(NULL, wxID_ANY, title, pos, size),
	_schem(nullptr)
{
	SetMinSize(wxSize(150, 150));
	SetIcon(wxICON(logo));
    wxMenu *menuFile = new wxMenu;
    menuFile->Append(ID_Hello, "&Open...\tCtrl-O");
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);
    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);
    wxMenuBar *menuBar = new wxMenuBar;
    wxMenu *menuView = new wxMenu;

    wxMenu *menuTexturePacks = new wxMenu;

	SelectedTP = menuTexturePacks->Append(ID_Texturepack0, "Default", wxEmptyString, wxITEM_CHECK);
	SelectedTP->Check(true);
	menuTexturePacks->Append(wxID_SEPARATOR);

	wxDir dir;
	wxString path = wxString(getenv("appdata")) + "\\.minecraft\\texturepacks";

	dir.Open(path);

	wxString fileName;
	bool cont = dir.GetFirst(&fileName, "*.zip", wxDIR_FILES);
	int inc = 1;

	TexturePacks[ID_Texturepack0] = wxEmptyString;

	while (cont)
	{
		auto id = ID_Texturepack0 + inc;
		menuTexturePacks->Append(id, fileName, wxEmptyString, wxITEM_CHECK);
		TexturePacks[id] = path + '\\' + fileName;

		cont = dir.GetNext(&fileName);
		++inc;
	}

	menuView->AppendSubMenu(menuTexturePacks, "Texture Packs");

	menuView->Append(wxID_SEPARATOR);
    menuView->Append(wxID_ZOOM_OUT, "Zoom Out\t,");
    menuView->Append(wxID_ZOOM_IN, "Zoom In\t.");
	menuView->Append(wxID_SEPARATOR);
    menuView->Append(ID_Modules, "Modules\tm");

	menuBar->Append( menuFile, "&File" );
    menuBar->Append( menuView, "&View" );
    menuBar->Append( menuHelp, "&Help" );
    SetMenuBar( menuBar );

	//_viewport0 = new wxViewportGLCanvas(this);
	//_viewport0->CreateContext();
	_viewport1 = new wxViewportGLCanvas(this);
	_viewport1->CreateContext();
	//_viewport2 = new wxViewportGLCanvas(this);
	//_viewport2->CreateContext(_viewport0->GetContext());
	//_viewport3 = new wxViewportGLCanvas(this);
	//_viewport3->CreateContext(_viewport0->GetContext());

	//_viewport0->SetWindowStyleFlag(wxBORDER_SIMPLE);
	//_viewport1->SetWindowStyleFlag(wxBORDER_SIMPLE);
	//_viewport2->SetWindowStyleFlag(wxBORDER_SIMPLE);
	//_viewport3->SetWindowStyleFlag(wxBORDER_SIMPLE);

	_viewport1->CreateControl(Viewport_Top);
	//_viewport0->CreateControl(Viewport_Left);
	//_viewport3->CreateControl(Viewport_Front);

	// begin wxGlade: MyFrame::do_layout
	/*wxGridSizer* grid_sizer_1 = new wxGridSizer(2, 2, 0, 0);
	grid_sizer_1->Add(_viewport0, 1, wxEXPAND, 0);
	grid_sizer_1->Add(_viewport1, 1, wxEXPAND, 0);
	grid_sizer_1->Add(_viewport2, 1, wxEXPAND, 0);
	grid_sizer_1->Add(_viewport3, 1, wxEXPAND, 0);
	SetSizer(grid_sizer_1);
	Layout();*/
	//wxGridSizer *sizer = new wxGridSizer(1, 1, 0, 0);
	//sizer->Add(_viewport1, 1, wxEXPAND);
	//SetSizer(sizer);
	//AddChild(_viewport1);
	//Layout();
	// end wxGlade
}

MyFrame *frame;

void MyFrame::OnExit(wxCommandEvent& event)
{
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxLaunchDefaultBrowser("http://planetminecraft.com/member/paril");
}

Schematic *_schematic;
void MyFrame::OnHello(wxCommandEvent& event)
{
	wxFileDialog* OpenDialog = new wxFileDialog(
		this, _("Choose a file to open"), wxEmptyString, wxEmptyString, 
		_("Schematics (*.schematic)|*.schematic"),
		wxFD_OPEN, wxDefaultPosition);
 
	// Creates a "open file" dialog with 4 file types
	if (OpenDialog->ShowModal() == wxID_OK) // if the user click "Open" instead of "Cancel"
	{
		auto &path = OpenDialog->GetPath();

		Schematic *schematic = new Schematic(path.ToStdString(), wxViewportGLCanvas::_renderer);

		if (!schematic->Loaded)
		{
			wxMessageBox(wxString("The schematic ") << path << " could not be loaded. Format not supported.", "Error");

			delete schematic;
			schematic = _schematic = nullptr;
		}
		
		frame->SetSchematic(schematic);

		if (_schematic != nullptr)
		{
			delete _schematic;
			_schematic = schematic;
		}

		SetTitle(verString + " - " + OpenDialog->GetFilename()); // Set the Title to reflect the file open
	}
 
	// Clean up after ourselves
	OpenDialog->Destroy();
}

void MyFrame::OnZoomOut(wxCommandEvent& event)
{
	_viewport1->GetControl()->SetScale(_viewport1->GetControl()->GetScale() / 2);
	//_viewport0->GetControl()->SetScale(_viewport0->GetControl()->GetScale() / 2);
	//_viewport3->GetControl()->SetScale(_viewport3->GetControl()->GetScale() / 2);
}

void MyFrame::OnZoomIn(wxCommandEvent& event)
{
	_viewport1->GetControl()->SetScale(_viewport1->GetControl()->GetScale() * 2);
	//_viewport0->GetControl()->SetScale(_viewport0->GetControl()->GetScale() * 2);
	//_viewport3->GetControl()->SetScale(_viewport3->GetControl()->GetScale() * 2);
}

void MyFrame::OnModules(wxCommandEvent& event)
{
	ModuleWindow *window = new ModuleWindow(wxViewportGLCanvas::_renderer->Renderers->GetScriptEngine(), this, "Modules", this->GetPosition(), wxSize(700, 450));
	window->ShowModal();
	delete window;
}

void MyFrame::OnTexturePack (wxCommandEvent& event)
{
	SelectedTP->Check(false);

	SelectedTP = SelectedTP->GetMenu()->FindChildItem(event.GetId());
	SelectedTP->Check(true);

	Control2DBase::GetSchematicMutex()->Lock();
	wxViewportGLCanvas::_renderer->MakeCurrent(_viewport1, _viewport1->GetContext());
	wxViewportGLCanvas::_renderer->SetTexturePack(TexturePacks[event.GetId()].c_str().AsChar());

	_viewport1->GetControl()->Refresh();
	Control2DBase::GetSchematicMutex()->Unlock();
}

void MyFrame::SetSchematic (Schematic *schematic)
{
	if (_schem == nullptr)
		delete _schem;

	_viewport1->GetControl()->SetSchematic(schematic);
	//_viewport0->GetControl()->SetSchematic(schematic);
	//_viewport3->GetControl()->SetSchematic(schematic);
}

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(ID_Hello, MyFrame::OnHello)
    EVT_MENU(ID_Modules, MyFrame::OnModules)
	EVT_MENU_RANGE(ID_Texturepack0, ID_TexturepackEnd, MyFrame::OnTexturePack)
    EVT_MENU(wxID_EXIT, MyFrame::OnExit)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
	EVT_MENU(wxID_ZOOM_OUT, MyFrame::OnZoomOut)
	EVT_MENU(wxID_ZOOM_IN, MyFrame::OnZoomIn)
wxEND_EVENT_TABLE()


bool MyApp::OnInit()
{
	frame = new MyFrame(verString, wxDefaultPosition, wxSize(700, 700));
    frame->Show(true);
    return true;
}

#include <wx\filename.h>

int MyApp::OnExit()
{
	wxFileName::Rmdir("temp", wxPATH_RMDIR_RECURSIVE);
	return wxApp::OnExit();
}

wxIMPLEMENT_APP(MyApp);
